/*
    Copyright (c) 2006-2007 Ivaylo Ivanov

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
*/
package com.avalonsql.core.db;

import com.avalonsql.core.db.connection.ConnectionWrapper;
import com.avalonsql.core.db.drivers.DBDriver;
import com.avalonsql.core.db.objects.api.IRootObject;
import com.avalonsql.core.db.objects.impl.Catalog;
import com.avalonsql.core.db.objects.impl.DBObject;
import com.avalonsql.core.db.objects.impl.Schema;

import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.zip.ZipEntry;
import java.util.jar.JarInputStream;
import java.sql.SQLException;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;

import org.apache.log4j.Logger;

public class Utils {

    public static String JAR_PREFIX = "/".equals(File.separator) ? "jar:file://" : "jar:file:/";

    protected static Logger logger = Logger.getLogger(Utils.class);

    private Utils() {
    }

    public static boolean isEmpty(String str) {
        return str != null && str.equals("");
    }

    public static URL[] readJars(String path) {
        if (path == null) {
            throw new IllegalArgumentException("path = null");
        }
        File file = new File(path);
        File[] jdbcJars = file.listFiles();
        URL[] url = new URL[jdbcJars.length];
        for (int i = 0; i < jdbcJars.length; i++) {
            url[i] = readJar(jdbcJars[i]);
        }
        return url;
    }

    public static URL readJar(File file) {
        if (file == null) {
            throw new IllegalArgumentException("file = null");
        }
        try {
            return new URL(JAR_PREFIX + file.getAbsolutePath() + "!/");
        } catch (MalformedURLException e) {
            logger.warn(e);
        }
        return null;
    }

    public static List loadJars(String path) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (path == null) {
            throw new IllegalArgumentException("path = null");
        }
        URL[] url = Utils.readJars(path);
        URLClassLoader urlClassLoader = new URLClassLoader(url);

        List result = new ArrayList();
        File file = new File(path);
        File[] jarFile = file.listFiles();
        if (jarFile != null) {
            for (int i = 0; i < jarFile.length; i++) {
                if (jarFile[i].isFile() && jarFile[i].getName().endsWith(".jar")) {
                    JarInputStream jarInputStream = new JarInputStream(new FileInputStream(jarFile[i].getPath()));
                    ZipEntry zipEntry;
                    while ((zipEntry = jarInputStream.getNextEntry()) != null) {
                        if (!zipEntry.isDirectory() && zipEntry.getName().endsWith(".class")) {
                            result.add(
                                    Class.forName(zipEntry.getName().replace("/", ".").replace(".class", ""), true, urlClassLoader).newInstance()
                            );
                        }
                    }
                }
            }
        }
        return result;
    }

    public static Map<String, String> getConnectionMetaData(ConnectionWrapper connectionWrapper) throws DBException {
        try {
            Map<String, String> result = new HashMap<String, String>();
            DatabaseMetaData connectionMetaData = connectionWrapper.getConnection().getMetaData();
            result.put("Catalog Term", String.valueOf(connectionMetaData.getCatalogTerm()));
            result.put("Catalog Separator", String.valueOf(connectionMetaData.getCatalogSeparator()));
            try {
                result.put("Database Major Version", String.valueOf(connectionMetaData.getDatabaseMajorVersion()));
            } catch (Throwable e) {
                result.put("Database Major Version", null);
            }
            try {
                result.put("Database Minor Version", String.valueOf(connectionMetaData.getDatabaseMinorVersion()));
            } catch (Throwable e) {
                result.put("Database Minor Version", null);
            }
            result.put("Database Product Name", connectionMetaData.getDatabaseProductName());
            result.put("Database Product Version", connectionMetaData.getDatabaseProductVersion());
            result.put("Default Transaction Isolation", String.valueOf(connectionMetaData.getDefaultTransactionIsolation()));
            result.put("Driver Major Version", String.valueOf(connectionMetaData.getDriverMajorVersion()));
            result.put("Driver Minor Version", String.valueOf(connectionMetaData.getDriverMinorVersion()));
            result.put("Driver Name", connectionMetaData.getDriverName());
            result.put("Driver Version", connectionMetaData.getDriverVersion());
            result.put("Extra Name Characters", connectionMetaData.getExtraNameCharacters());
            result.put("Identifier Quote String", connectionMetaData.getIdentifierQuoteString());
            try {
                result.put("JDBC Major Version", String.valueOf(connectionMetaData.getJDBCMajorVersion()));
            } catch (Throwable e) {
                result.put("JDBC Major Version", null);
            }
            try {
                result.put("JDBC Minor Version", String.valueOf(connectionMetaData.getJDBCMinorVersion()));
            } catch (Throwable e) {
                result.put("JDBC Minor Version", null);
            }

            result.put("Max Binary Literal Length", String.valueOf(connectionMetaData.getMaxBinaryLiteralLength()));
            result.put("Max Catalog Name Length", String.valueOf(connectionMetaData.getMaxCatalogNameLength()));
            result.put("Max Char Literal Length", String.valueOf(connectionMetaData.getMaxCharLiteralLength()));
            result.put("Max Column Name Length", String.valueOf(connectionMetaData.getMaxColumnNameLength()));
            result.put("Max Columns In Group By", String.valueOf(connectionMetaData.getMaxColumnsInGroupBy()));
            result.put("Max Columns In Index", String.valueOf(connectionMetaData.getMaxColumnsInIndex()));
            result.put("Max Columns In Order By", String.valueOf(connectionMetaData.getMaxColumnsInOrderBy()));
            result.put("Max Columns In Select", String.valueOf(connectionMetaData.getMaxColumnsInSelect()));
            result.put("Max Columns In Table", String.valueOf(connectionMetaData.getMaxColumnsInTable()));
            result.put("Max Connections", String.valueOf(connectionMetaData.getMaxConnections()));
            result.put("Max Cursor Name Length", String.valueOf(connectionMetaData.getMaxCursorNameLength()));
            result.put("Max Index Length", String.valueOf(connectionMetaData.getMaxIndexLength()));
            result.put("Max Procedure Name Length", String.valueOf(connectionMetaData.getMaxProcedureNameLength()));
            result.put("Max Row Size", String.valueOf(connectionMetaData.getMaxRowSize()));
            result.put("Max Schema Name Length", String.valueOf(connectionMetaData.getMaxSchemaNameLength()));
            result.put("Max Statement Length", String.valueOf(connectionMetaData.getMaxStatementLength()));
            result.put("Max Statements", String.valueOf(connectionMetaData.getMaxStatements()));
            result.put("Max Table Name Length", String.valueOf(connectionMetaData.getMaxTableNameLength()));
            result.put("Max Tables In Select", String.valueOf(connectionMetaData.getMaxTablesInSelect()));
            result.put("Max User Name Length", String.valueOf(connectionMetaData.getMaxUserNameLength()));


            result.put("Procedure Term", String.valueOf(connectionMetaData.getProcedureTerm()));

            try {
                result.put("Close Cursor At Commit", String.valueOf(connectionMetaData.getResultSetHoldability() == ResultSet.CLOSE_CURSORS_AT_COMMIT));
            } catch (Throwable e) {
                result.put("Close Cursor At Commit", null);
            }

            result.put("Schema Term", String.valueOf(connectionMetaData.getSchemaTerm()));
            result.put("Search String Escape", String.valueOf(connectionMetaData.getSearchStringEscape()));

            return result;
        } catch (SQLException e) {
            throw new DBException(e);
        }
    }

    public static void setCaption(DBDriver dbDriver, DBObject dbObject) {
        Class<? extends IRootObject> databaseRootObjectClass = dbDriver.getDatabaseRootObjectClass();
//        if (!databaseRootObjectClass.equals(dbDriver.getRootObjectClass())) {
            String name = dbObject.getName();
            if (databaseRootObjectClass.isAssignableFrom(Catalog.class)) {
                dbObject.setCaption(dbObject.getCatalog() + "." + name);
            } else if (databaseRootObjectClass.isAssignableFrom(Schema.class)) {
                dbObject.setCaption(dbObject.getSchema() + "." + name);
            }
       // }
    }

}
